Skip to content

feat(qa): resolve platform-checklist symbol anchors against real source - #15159

Merged
baozhoutao merged 3 commits into
mainfrom
claude/issue-13788-checklist-symbol-anchor-resolver
Sep 4, 2026
Merged

feat(qa): resolve platform-checklist symbol anchors against real source#15159
baozhoutao merged 3 commits into
mainfrom
claude/issue-13788-checklist-symbol-anchor-resolver

Conversation

@baozhoutao

@baozhoutao baozhoutao commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #13788

Step (2) of #13482's ruling — the half PR #13786 (step (1), the :NNN strip) deliberately deferred.

⚠️ What a red from this resolver actually reaches — read this first

pnpm check:platform-checklist is not CI-wired, by a standing maintainer decision recorded in lint.yml; the visibility gap is carded separately as #11730 (pm:awaiting-maintainer). ⇒ A red from this resolver reaches whoever runs the gate, not every PR. No CI wiring is touched here — that decision is the maintainer's and #11730 holds it. Stating this plainly is part of the deliverable: overstating a new check's reach would reproduce the very defect this family is closing — a signal that reads as verified while pointing at nothing.

The defect

After step (1) a citation is file plus the symbol it lands in, so nothing rots on an unrelated edit. But nothing resolved it: a symbol renamed or deleted out of the cited file left the citation reading exactly as it did the day it was verified — exit-0 by construction, the same shape the line numbers had, one level up. This PR found one of those live: registerRecordShareEndpoints has not been in rest-server.ts for some time (the record-shares routes are registered inline, under no registrar of their own), and the citation naming it had been reading as verified the whole time.

What landed

  1. The citations are re-authored as structured symbol anchors, spelled inline so the prose that carries a citation's reason survives the change:

    packages/core/src/security/platform-admin.ts#parsePlatformAdminEmails

    The #symbol half is the machine-readable pin; everything around it is untouched. Rewriting each citation into a bare object per entry would have thrown the reasons away across the whole ledger.

  2. A resolver in scripts/check-platform-checklist.mjs, extending the mechanism the gate already had for enumSource {file, export, expect}. It reds when the cited file is absent, when the extension carries no symbols this gate can read, and when the cited symbol is not in the file outside its comments — every segment of a dotted anchor, not only the first.

    Deliberately dumb, presence-level, house-ledger style: presence-in-code at identifier boundaries, not a declaration analysis. A symbol surviving only in a docblock is absent (prose about a symbol is not a symbol); a symbol inside a string literal counts as present (much of what this ledger cites is a string — capability names, error codes, sys_* machine names). Both directions are stated in the gate header and the README rather than left to be discovered.

  3. A shrink-never floorscripts/checklist-symbol-anchor-baseline.json, one entry per family file, authored from the new read-only --anchor-census mode. Every red this resolver prints has a second, silent remedy: delete the #symbol half and the citation drops back to prose the gate does not read. The floor closes that door, and makes the green say a number instead of meaning nothing once the population reaches zero. Lowering a floor is marked ⛔ MAINTAINER-ONLY per the check:engine-double-contract fires at CI time, not authoring time — four independent PRs tripped it on brand-new test files in one shift, and a pre-warning in the brief did not prevent it #8435 convention; the roster's own size is pinned beside it, since deleting an entry silences a floor as effectively as zeroing it.

  4. Two-direction pins for every rule in the gate's existing multi-entry self-test dispatch (141 → 176 assertions), plus the battery roster floor the file's own handshake comment argued for: the flags answer "did this battery reach its verdict", and the roster answers the other half — a battery that reaches its verdict having run fewer assertions reports a smaller number every leg below reads as a pass.

  5. Two line-pin spellings step (1) could not reach, measured rather than reasoned while sweeping for anchorable citations: AiChatPage.tsx:~605-615 (the tilde inside the colon form — the battery only ever pinned ~:) and ~L7246-7331, which carries no colon at all. Four survivors, all repaired; the detector gains both branches with a left and right boundary on the L form so SQL2019 / L10n / L1 stay silent.

The census, re-derived (not inherited)

measured on origin/main = ebb08220
source citation entries 1,376 in → 1,376 out — no citation created or destroyed
items / area files 260 items · 15 area files (the card quoted 1,647 / 18 from #13786's criterion; both re-measured here)
symbol anchors authored 610, across 15 area files + README
anchors that resolve 610 / 610
ledger diff 596 changed lines: 593 are pure #symbol insertions, 3 are the deliberate line-pin repairs (proved mechanically — stripping every anchor from each added line reproduces the removed line byte-for-byte)

Verification record

Every exit code captured by redirect before any pipe.

The gate's own suite, both halves

EXIT=0 :: node scripts/check-platform-checklist.mjs --self-test    # 176 assertions (was 141)
EXIT=1 :: node scripts/check-platform-checklist.mjs                # 4 problems — see below

⚠️ check-platform-checklist exits 1 on main today, before this branch exists: four capabilities (batch_endpoints, crud_endpoints, metadata_endpoints, route_generation) are UNCLASSIFIED in coverage.json. Measured on a clean worktree at origin/main before the first edit, and the error set after this change is byte-identical to it (diff of the two lists is empty) — zero new problems, and none of the four is this PR's to fix. Filed as #15167; authoring or waiving four REST capability areas is checklist-author content work, and folding it in here would have made both changes unreviewable.

Derived gate family (node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, re-derived after the change set grew — same family both times)

EXIT=0 :: node scripts/check-ci-filter-parity.mjs
EXIT=0 :: node scripts/check-closing-keyword-parity.mjs            (+ --self-test)
EXIT=0 :: node scripts/check-comment-mask-corpus.mjs
EXIT=0 :: node scripts/check-self-test-wired.mjs                   (+ --self-test)
EXIT=0 :: node scripts/check-whole-set-label-write.mjs             (+ --self-test)

A first pass exited 3 (PREREQUISITE NOT MET) on three of these — an uninstalled worktree, NOT MEASURED and never a pass. pnpm install --frozen-lockfile (EXIT=0), then re-run: the codes above.

Always-runs tail

EXIT=0 :: pnpm check:pm-dispatch-gates
EXIT=0 :: pnpm check:declared-population-live
EXIT=0 :: pnpm check:ratchet-remedy-authority
EXIT=0 :: pnpm check:nul-bytes
EXIT=0 :: node scripts/check-self-test-wired.mjs
EXIT=0 :: npx eslint scripts/check-platform-checklist.mjs scripts/pm/dispatch-gates.mjs

check:pm-dispatch-gates first failed 1 of 1,343 cases — the new battery owed a COMPOUND_ANCHOR_LEDGER row in scripts/pm/dispatch-gates.mjs. Registered (false, beside its five siblings in the same gate); 1,343/1,343 pass. There is no check:self-test-wired pnpm alias in this repo — the script is invoked directly, and is green both ways.

Ablation — the absent-symbol check

  1. an anchor naming a symbol that is not in the cited file, authored into areas/i18n.json → gate EXIT=1, 5 problems, the fifth being ABSENT SYMBOL — …#zzzRetiredSymbolThatIsGone;
  2. the same ledger with absentAnchorSegments neutered in memory → 4 problems, 0 non-coverage — proof the red is this check's and nothing else's;
  3. both restored → 4 problems, working tree clean against HEAD.

Ablation — the roster floor
Two rows deleted from the symbol-anchor battery → --self-test EXIT=1: battery "selfTestSymbolAnchors…" reported 27 assertions but its floor is 29, and the inline leg refuses too (assertions stopped running, and every leg below would read the smaller count as a pass). Restored → EXIT=0.

Control bytes: all 19 changed files scanned, clean; this body scanned too.

Scope fence

  • ⛔ No CI wiring, per the top of this body.
  • No governed surface (docs/adr/**, .claude/**, skills/**, AGENTS.md, CLAUDE.md) and nothing under content/docs/releases/.
  • One file outside the card's expected surface: scripts/pm/dispatch-gates.mjs, one ledger row, because the dispatch-gates self-test demands the registration — declared rather than done silently.
  • No changeset: this diff publishes nothing from any released package (scripts/ + docs/qa/ only), which is what the skip-changeset label is for.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TouCuN9vQdktkP2MAEgnDC

Step (2) of #13482's ruling, deferred by PR #13786 (step (1), which stripped
the rotting `:NNN` suffixes). A citation of `file` plus the symbol it lands in
does not rot on an unrelated edit — but nothing RESOLVED it, so a symbol
renamed or deleted out of the cited file left the citation reading exactly as
it did the day it was verified.

- re-author the citations as structured symbol anchors, spelled inline as
  `path/to/file.ts#symbolName` so the prose that carries a citation's reason
  survives the change: 609 anchors across the 15 area files;
- a resolver in `check-platform-checklist.mjs` that reds when the cited file is
  absent, when its extension carries no symbols this gate can read, or when the
  cited symbol is not in the file outside its comments — every segment of a
  dotted anchor, not just the first;
- a shrink-never per-file floor (`scripts/checklist-symbol-anchor-baseline.json`,
  authored from the new `--anchor-census` mode) so the resolver's population
  cannot be emptied one deleted `#symbol` at a time — the silent remedy every
  red here would otherwise have;
- 29 self-test rows, two-directional on all three limbs, plus the battery
  roster floor the file's own handshake comment argued for.

Refs #13788

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TouCuN9vQdktkP2MAEgnDC
… the anchor

Measured while sweeping the ledger for anchorable citations: four line pins
survived PR #13786 in two spellings its detector cannot reach — `AiChatPage
.tsx:~605-615` (the tilde INSIDE the colon form; the battery only ever pinned
`~:`) and `~L7246-7331`, which carries no colon at all. Both read exactly like
the class step (1) removed, and both sat green through it.

- the detector gains both branches, with a left AND right boundary on the `L`
  form so `SQL2019` / `L10n` / `L1` stay silent (six new rows, both directions);
- the four citations are repaired — and repairing one surfaced what the
  resolver is for: `registerRecordShareEndpoints` has not been in
  `rest-server.ts` for some time (the record-shares routes are registered
  inline, under no registrar of its own), so the citation had been naming
  nothing while reading as verified;
- README gains the anchor spelling, what is anchorable and why an unresolvable
  citation stays BARE, the shrink-never floor and its ⛔ MAINTAINER-ONLY
  authority — and the note that a red here reaches whoever runs the gate, not
  every PR (#11730);
- the battery roster floors are set from measured counts.

Refs #13788

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TouCuN9vQdktkP2MAEgnDC
…ledger

`check:pm-dispatch-gates` reds on a compound self-test name its
COMPOUND_ANCHOR_LEDGER does not classify — the registration the new
`selfTestSymbolAnchors` battery owes. Classified `false` beside its five
siblings in the same gate: it IS a self-test battery, so its fixtures should be
masked away.

Refs #13788

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TouCuN9vQdktkP2MAEgnDC
@baozhoutao baozhoutao added tooling skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed documentation Improvements or additions to documentation size/xl labels Sep 4, 2026 — with Claude

Copy link
Copy Markdown
Contributor Author

Status on the two CI reds relayed for head a7d97646both were already addressed on the current head 51ee6d0, which is what the branch has carried since 04:33Z. Neither needed a new push; the evidence and one thing that needs a PM ruling are below.

1. PM dispatch-gates self-test — fixed in 51ee6d0, and the fix is the registration that gate prescribes, not a dodge.

The failing assertion was precise about what it wanted:

✗ every compound self-test NAME the anchor matches is classified in
  COMPOUND_ANCHOR_LEDGER — unlisted: scripts/check-platform-checklist.mjs::selfTestSymbolAnchors

No new check:* or package.json script was added by this PR (git diff --name-only origin/main...HEAD carries no package.json), so the hypothesis in the relay — that a new script key demanded CI wiring #11730 forbids — does not hold here. The resolver lives inside the existing check:platform-checklist entry exactly as the card requires.

⚠️ The relay said ⛔ do not edit dispatch-gates.mjs, and 51ee6d0 edits it — one row. Flagging rather than quietly keeping it: that file's own maintenance note makes the row the sanctioned remedy and names the opposite act as the forbidden one.

A compound-name declaration this table does not list reds check:pm-dispatch-gates. Classify it and add a row: accidental: false if it is a self-test battery (its fixtures SHOULD be masked away) … ⛔ Do not "repair" a red by renaming the function to dodge the anchor: the row is the record, and the next accidental name is the one nobody will notice.

So the row is classified false beside the five sibling batteries the same gate already declares, and no self-test case was touched or weakened. The alternative that would have satisfied the relay's letter — renaming selfTestSymbolAnchors out of the anchor's way — is the one thing that paragraph forbids. If the PM reads the fence as binding over the ledger's own note, say so and the battery gets renamed instead; I have not taken that decision unilaterally in either direction, and this comment is the record either way.

Local verdict on 51ee6d0, exit codes captured by redirect before any pipe:

EXIT=0 :: node scripts/pm/dispatch-gates.mjs --self-test     # 1343/1343 cases pass, 0 ✗
EXIT=0 :: pnpm check:pm-dispatch-gates

2. Check Changeset — the skip-changeset label was applied at 04:34Z (after the relayed run), and the job now reports skipped on the current head, which is the exemption working rather than a red. Per AGENTS.md the label is for "a diff that publishes nothing from any released package", and this diff is scripts/ + docs/qa/ only. lint.yml's own comment beside that gate calls this case by name:

And "this PR edits a CI-internal script" is the textbook skip-changeset case — such a PR releases nothing, so by the workflow's own prescription it takes the label.

The changeset-family self-tests stay unconditional in Lint & Repo Gates, so the label does not exempt anything that verifies this PR's own work.

Full local re-run on 51ee6d0 (derived family re-derived after the change set grew — same 8 commands): all EXIT=0, plus check:declared-population-live, check:ratchet-remedy-authority, check:nul-bytes, node scripts/check-self-test-wired.mjs (there is no pnpm alias for that one in this repo) and eslint over both changed scripts. The gate's own two halves: --self-test EXIT=0 at 176 assertions; the normal mode EXIT=1 with exactly the four coverage.json UNCLASSIFIED problems that are on main before this branch exists ( lists diff empty; filed as #15167).

Remote CI on 51ee6d0 was still in progress when this was written — Test Core 6/6, Dogfood Regression Gate, Type Check · source gates and Governed Surface Queue Guard green, Lint & Repo Gates not yet reported. Subscribed to this PR's activity; I will act on the Lint & Repo Gates result when it lands rather than reading a partial board as green.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

CI board on head 51ee6d0, read rather than assumed — one correction to my previous comment and one item still open.

Check Changeset — the red is real but superseded, and its own text says by what. The failing run (33837243343, job 100912155506) started 04:33:23Z and failed 04:34:01Z with:

This PR adds no changeset. If it releases nothing (including any skills/** change — see #5947), apply the skip-changeset label; otherwise run pnpm changeset and name the packages.

The skip-changeset label was applied at ~04:34:28Z — 27 seconds after that job failed — and every re-publication of the job since (runs 33837312890, 33837313306, 33837313386, 33837313876) reports skipped, which is the job-level exemption taking effect. So the red is a pre-label artifact of one run, not a standing failure, and it is not in the six required contexts. ⛔ No empty commit and no re-run to clear it: the next push that lands for any real reason re-publishes it as skipped. Correcting my earlier phrasing — I said the job "now reports skipped", which was true of the later runs but glossed over the fact that a genuine failure conclusion from the pre-label run is still on the board.

Green so far on 51ee6d0: Test Core (6/6 shards + rollup), Dogfood Regression Gate, Type Check · source gates, Type Check · consumer gates, Check PR Size, Check Documentation Links, Governed Surface Queue Guard, Part-of PR must not also close its card, and both single-writer/issue-claim guards.

Still open: Lint & Repo Gates (job 100912155561) and two Type Check legs are in_progress — that job is where PM dispatch-gates self-test lives, i.e. the step the relay reported red on the previous head. Locally on this exact head it is green (node scripts/pm/dispatch-gates.mjs --self-test → EXIT=0, 1343/1343; pnpm check:pm-dispatch-gates → EXIT=0), but a local green is not the board's. Check-in armed; if that job comes back red I fix it in the diff and push, and if it comes back green I say so here with the sha.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

Green on head 51ee6d0a0f8835cbcb0004eca2b741e26c888614: Lint & Repo Gates success (job 100912155561, 04:48:37Z — the job carrying PM dispatch-gates self-test, red on the previous head), and the four other gate-carrying required contexts are success too (TypeScript Type Check, Test Core, Dogfood Regression Gate; Build Core and Temporal Conformance skipped on their paths filters). Check Changeset is success on the PM's re-run with the skip-changeset label present. No commits were needed for either; PR stays draft and unarmed, and the full reconciliation of the citation census is on #13788 (comment 5535865458).


Generated by Claude Code

@baozhoutao
baozhoutao marked this pull request as ready for review September 4, 2026 05:35
@baozhoutao
baozhoutao enabled auto-merge September 4, 2026 05:35
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 6757634 Sep 4, 2026
51 of 52 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13788-checklist-symbol-anchor-resolver branch September 4, 2026 06:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changeset PR has no user-facing published change; bypasses the changeset gate tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

platform-checklist step (2): re-author the 1,647 source citations as symbol anchors and add a resolver that reds on an absent symbol

2 participants